
import React, { Component } from 'react';

import {
  NativeModules,
  TextInput,
  findNodeHandle,
  AppRegistry,
  AccessibilityInfo,
  Platform
} from 'react-native';
import PropTypes from 'prop-types'

const { CustomKeyboard } = NativeModules;

const {
  install, uninstall, getSelectionRange,
  insertText, backSpace, doDelete,
  moveLeft, moveRight,
  switchSystemKeyboard,
} = CustomKeyboard;

export {
  install, uninstall, getSelectionRange,
  insertText, backSpace, doDelete,
  moveLeft, moveRight,
  switchSystemKeyboard,
};

const keyboardTypeRegistry = {};
const defaultKeyboardHeight = 216

export function register(type, keyboardInfo) {
  keyboardTypeRegistry[type] = keyboardInfo;
}
const getKeyboardHeightByType = (type) => {
  const height = keyboardTypeRegistry[type].height
  return height || defaultKeyboardHeight
}

class CustomKeyboardContainer extends Component {
  render() {
    const {tag, type} = this.props;
    const factory = keyboardTypeRegistry[type].factory;
    const inputFilter = keyboardTypeRegistry[type].inputFilter
    if (!factory) {
      console.warn(`Custom keyboard type ${type} not registered.`);
      return null;
    }
    const Comp = factory();
    return <Comp tag={tag} inputFilter={inputFilter} />;
  }
}

AppRegistry.registerComponent("CustomKeyboard", ()=>CustomKeyboardContainer);

export class CustomTextInput extends Component {
  static propTypes = {
    ...TextInput.propTypes,
    customKeyboardType: PropTypes.string,
  };

  constructor () {
    super()
    this._isA11yEnable = false;
    this._installCustomInput = this._installCustomInput.bind(this)
    AccessibilityInfo.addEventListener('change', this._changeListener)
    AccessibilityInfo.fetch().then((isEnable) => {
      this._isA11yEnable = isEnable;
    })
  };

  _changeListener = (isEnable) => {
    this._isA11yEnable = isEnable;
  }
  componentDidMount() {
    this._installCustomInput()
  }

  componentWillUnmount () {
    AccessibilityInfo.removeEventListener('change', this._changeListener)
  }

  componentWillReceiveProps(newProps) {
    if (newProps.customKeyboardType !== this.props.customKeyboardType || newProps.maxLength !== this.props.maxLength) {
      install(
          findNodeHandle(this.input),
          newProps.customKeyboardType,
          newProps.maxLength === undefined ? 1024 : newProps.maxLength,
          getKeyboardHeightByType(newProps.customKeyboardType)
      );
    }
  }

  _installCustomInput () {
    if (Platform.OS === 'ios') {
      // 为了解决 iOS 还未完成 AppRegistry.registerComponent 就调用了 install 方法，造成展示了系统键盘的问题，需要给 install 加个延时
      // 为了避免系统键盘闪现，刚开始不设置 autoFocus，延时设置
      setTimeout(() => {
        install(
            findNodeHandle(this.input),
            this.props.customKeyboardType,
            this.props.maxLength === undefined ? 1024 : this.props.maxLength,
            getKeyboardHeightByType(this.props.customKeyboardType)
        );
        const { autoFocus } = this.props
        if (autoFocus && this.input) {
          let number = findNodeHandle(this.input);
          TextInput.State.focusTextInput(number);
        }
      }, 10)
    } else {
      install(
          findNodeHandle(this.input),
          this.props.customKeyboardType,
          this.props.maxLength === undefined ? 1024 : this.props.maxLength,
          getKeyboardHeightByType(this.props.customKeyboardType)
      );
    }
  }

  onRef = ref => {
    if (ref) {
      this.input = ref;
    }
  };

  onFocus = (target) => {
    /**
     * 这里要这么处理的原因是在某些情况下，焦点聚焦之后，获取到的currentlyFocusedNumber是一个空值，会导致TextInput的State配置
     * 与实际情况不符合，所以在触发了聚焦事件之后，手动更新一次当前的currentlyFocusedNumber
     */
    const foucusNumber = TextInput.State.currentlyFocusedField();
    if (!foucusNumber) {
      let number = findNodeHandle(this.input);
      TextInput.State.focusTextInput(number);
    }

    const onFocus = this.props.onFocus
    if(onFocus && typeof onFocus === 'function'){
      try{
        onFocus(target)
      } catch(e){
        console.error(e)
      }
    }
  };

  onSelectionChange = (selection) => {
    /**
     * 此处这么处理的原因是某些读屏场景下，无障碍焦点聚焦之后，selection会出现指为-1的情况，此时没有光标，输入文案的时候，会插入在
     * 输入框的0号位置，所以会出现倒叙输入的情况，修复方案为每次监测到selection变化后，如果为-1，那么手动重置一次selection的位置
     * */
    if (this._isA11yEnable && selection && selection.nativeEvent && selection.nativeEvent.selection) {
      let start = selection.nativeEvent.selection.start
      let end = selection.nativeEvent.selection.end
      if (start === -1 && end === -1) {
        let thisInputNode = this.input
        if (thisInputNode) {
          if (thisInputNode.props && thisInputNode.props && thisInputNode.props.value) {
            let length = thisInputNode.props.value.length || 0
            if (thisInputNode.setNativeProps && typeof thisInputNode.setNativeProps === 'function') {
              thisInputNode.setNativeProps({
                selection:{ start: length, end: length }
              })
            }
          }
        }
      }
    }

    const onSelectionChange = this.props.onSelectionChange
    if (onSelectionChange && typeof onSelectionChange === 'function') {
      try {
        onSelectionChange(selection)
      } catch (e) {
        console.error(e)
      }
    }
  };


  render() {
    const { customKeyboardType, autoFocus, ...others } = this.props;
    return <TextInput {...others} autoFocus={(Platform.OS === 'ios') ? false : autoFocus} keyboardType={'numeric'} ref={this.onRef} onFocus={this.onFocus} onSelectionChange={this.onSelectionChange} />;
  }
}

